接下來兩天會實作簡單 Shopping cart 主要練習,數據驅動 UI
我們是一間高級餐廳,每日會提供限量餐點,因為預訂的客戶太多希望可以開發一套餐點預訂系統。
{
title: String,
image: String,
inventory: Number,
price: Number
},
主要使用 v-bind:class
語法糖: :class
取代過去我們使用 JQuery 在條件成立的時候要把 tag 的 class 換掉,
在 Vue 框架下可以使用數據,來驅動 UI 的變化,
使用聲明式宣告,把所有條件寫好在 UI 上,只要數據改變,UI 就會改變。
web | 人體 |
---|---|
HTML | 骨頭 |
CSS | 皮膚 |
JavaScript | 肌肉 |
JSON | 神經 |
web | 被蚊子叮的時候 | 人體 | vue & vuex |
---|---|---|---|
JSON | 神經反應 | 被叮了 | vuex 改變 staet |
JavaScript | 肌肉收縮 | X! 打蚊子! | state 改變 UI 更新資料 |
CSS | 皮膚改變 | 腫起來.. (用指甲畫十字) | 改變 class 或 style |
以上是練肖威.. :D
使用 Object 作為結構,
Object | 功能 |
---|---|
key | 條件成立時使用的 class |
value | 條件設定 (javascript) |
條件成立的時候,觸發 disabled
<template>
<div>
<!-- Top menu -->
<div class="w3-white w3-xlarge w3-padding-xlarge" style="max-width:1200px;margin:auto">
<div class="w3-right">
<router-link :to="{name: 'cart'}">
<!-- 顯示購物車總產品數 -->
<span class="glyphicon glyphicon-shopping-cart" aria-hidden="true"> {{ cartTotal }}</span>
</router-link>
</div>
<div class="w3-center">Shop</div>
</div>
<!-- !PAGE CONTENT! -->
<div class="w3-main w3-content w3-padding" style="max-width:1200px;margin-top:100px">
<div class="w3-row-padding w3-padding-16 w3-center" id="food">
<!--
產品列表
當產品庫存為: 0
使用 :class 加上 "w3-grayscale-max" class
-->
<div
v-for="(item, index) in foodList"
class="w3-quarter"
:class="{ 'w3-grayscale-max': !item.inventory }">
<img :src="item.image" style="width: 100%;">
<h3>{{ item.title }}</h3>
<h4>${{ item.price }}</h4>
<!--
數據驅動 UI
根據條件變化不同 class
當庫存為:0 的時候 ":disabled"
-->
<button
class="w3-btn w3-round-large w3-large w3-padding-large"
:class="{
'w3-red': item.inventory == 1,
'w3-green': item.inventory >= 2,
'w3-dark-grey': !item.inventory
}"
:disabled="!item.inventory"
@click="addCart( item.title )">
<span class="glyphicon glyphicon-shopping-cart" aria-hidden="true"></span>
<!--
數據驅動 UI
按鈕顯示文案
-->
<span v-if="item.inventory == 1">最後 {{ item.inventory }} 客</span>
<span v-if="item.inventory >= 2">限量 {{ item.inventory }} 客</span>
<span v-if="!item.inventory">Sold out</span>
</button>
</div><!-- end preduct -->
</div>
</div>
</div>
</template>
<script>
import { mapGetters, mapActions } from 'vuex';
export default {
computed: mapGetters({
foodList: 'getProducts',
cartTotal: 'getShoppingCartTotal'
}),
methods: mapActions([
'addCart'
]),
}
</script>
<!-- 載入 w3school - food blog template -->
<style src="../../static/css/w3.css"></style>
const types = {
ADD_CART: 'store/ADD_CART',
CANCEL_CART: 'store/CANCEL_CART'
}
const state = {
// 餐點列表
products: [
{
title: 'The Perfect Sandwich, A Real NYC Classic',
image: 'http://www.w3schools.com/w3images/sandwich.jpg',
inventory: 5,
price: 155
},
{
title: 'Let Me Tell You About This Steak',
image: 'http://www.w3schools.com/w3images/steak.jpg',
inventory: 1,
price: 1380
},
{
title: 'Cherries, interrupted',
image: 'http://www.w3schools.com/w3images/cherries.jpg',
inventory: 2,
price: 499
},
{
title: 'Once Again, Robust Wine and Vegetable Pasta',
image: 'http://www.w3schools.com/w3images/wine.jpg',
inventory: 3,
price: 790
}
],
// 購物車
shoppingCart: [],
}
const getters = {
// 取得餐點列表
getProducts: state => state.products,
// 取得購物車總數量
getShoppingCartTotal: state => state.shoppingCart.length,
}
const actions = {
addCart ({ commit }, id) {
commit(types.ADD_CART, id);
}
}
const mutations = {
[types.ADD_CART] (state, id) {
// ES6 array find 找到條件成立的內容。
const product = state.products.find(item => item.title === id && item.inventory !== 0);
// 餐點庫存 -1
product.inventory = product.inventory - 1;
// 餐點加入購物車 title, price
state.shoppingCart.push({
title: product.title,
price: product.price,
});
}
}
export default {
state,
getters,
actions,
mutations
}
實作小範例入門 Vue & Vuex 2.0 - github 完整範例
使用 git checkout 切換每天範例。